/**
  **********************************************************************************************************************
  * @file    param.c
  * @brief   该文件提供双向链表功能
  * @author  const_zpc  any question please send mail to const_zpc@163.com
  * @version V0.1
  * @date    2023-02-07
  *
  * @details  功能详细说明：
  *           + 迭代器
  *           + 元素访问
  *
  **********************************************************************************************************************
  * 源码路径：https://gitee.com/const-zpc/cot.git 具体问题及建议可在该网址填写 Issue
  *
  *
  **********************************************************************************************************************
  */

/* Includes ----------------------------------------------------------------------------------------------------------*/
#include "container/list.h"
#include <stdlib.h>
#include <string.h>


static cotListItem_t *CreatItem(const void *pdata, uint32_t length)
{
    cotListItem_t *p = (cotListItem_t *)malloc(sizeof(cotListItem_t) + length);

    if (p != NULL)
    {
        p->pData = &((uint8_t *)p)[sizeof(cotListItem_t)];
        p->length = length;
        memcpy(p->pData, pdata, length);
    }

    return p;
}

static void DestoryItem(cotListItem_t *pItem)
{
    free(pItem);
}

static void Insert(cotList_t *pList, cotListItem_t *pListItem, const void *pdata, uint32_t length)
{
    cotListItem_t *pItem = CreatItem(pdata, length);

    pItem->pPrev = pListItem->pPrev;
    pItem->pNext = pListItem;

    pListItem->pPrev->pNext = pItem;
    pListItem->pPrev = pItem;
    pList->count++;
}

static void Erase(cotList_t *pList, cotListItem_t *pListItem)
{
    pListItem->pPrev->pNext = pListItem->pNext;
    pListItem->pNext->pPrev = pListItem->pPrev;
    pList->count--;
    DestoryItem(pListItem);
}

static void Clear(cotList_t *pList)
{
    cotListItem_t *pCurItem = pList->node.pNext;

    while (pCurItem != &pList->node)
    {
        cotListItem_t *pTmp = pCurItem->pNext;
        Erase(pList, pCurItem);
        pCurItem = pTmp;
    }
}

/**
  * @brief      初始化一个链表
  * 
  * @param      pList  链表句柄
  */
void cotList_Init(cotList_t *pList)
{
    pList->node.pPrev = &pList->node;
    pList->node.pNext = &pList->node;
    pList->node.length = 0;
    pList->node.pData = NULL;
    pList->count = 0;
}

/**
  * @brief      迭代器开始指针
  * 
  * @param      pList  链表句柄
  * @return     链表元素指针
  */
cotListItem_t *cotList_Begin(cotList_t *pList)
{
    return pList->node.pNext;
}

/**
  * @brief      迭代器结束指针
  * 
  * @param      pList  链表句柄
  * @return     链表元素指针
  */
cotListItem_t *cotList_End(cotList_t *pList)
{
    return &pList->node;
}

/**
  * @brief      迭代器下一个元素
  * 
  * @attention  配合 cotList_Begin 和 cotList_End 使用
  * @param      pListItem 链表元素指针
  * @return     链表下一个元素指针
  */
cotListItem_t *cotList_Next(cotListItem_t *pListItem)
{
    return pListItem->pNext;
}

/**
  * @brief      反向迭代器开始指针
  * 
  * @param      pList  链表句柄
  * @return     链表元素指针
  */
cotListItem_t *cotList_rBegin(cotList_t *pList)
{
    return pList->node.pPrev;
}

/**
  * @brief      反向迭代器结束指针
  * 
  * @param      pList  链表句柄
  * @return     链表元素指针
  */
cotListItem_t *cotList_rEnd(cotList_t *pList)
{
    return &pList->node;
}

/**
  * @brief      反向迭代器下一个元素
  * 
  * @attention  配合 cotList_rBegin 和 cotList_rEnd 使用
  * @param      pListItem 链表元素指针
  * @return     链表下一个元素指针
  */
cotListItem_t *cotList_rNext(cotListItem_t *pListItem)
{
    return pListItem->pPrev;
}

/**
  * @brief      返回链表头元素指针
  * 
  * @param      pList 链表句柄
  * @return     头元素指针
  */
cotListItem_t *cotList_Front(cotList_t *pList)
{
    return pList->node.pNext;
}

/**
  * @brief      返回链表尾元素指针
  * 
  * @param      pList 链表句柄
  * @return     头元素指针
  */
cotListItem_t *cotList_Back(cotList_t *pList)
{
    return pList->node.pPrev;
}

/**
  * @brief      判断链表是否为空
  * 
  * @param      pList  链表句柄
  * @return     true   空
  * @return     false  非空
  */
bool cotList_Empty(cotList_t *pList)
{
    return pList->node.pNext == (&pList->node);
}

/**
  * @brief      获取链表元素数目
  * 
  * @param      pList 链表句柄
  * @return     元素数目 
  */
size_t cotList_Size(cotList_t *pList)
{
    return pList->count;
}

/**
  * @brief      清除链表所有元素
  * 
  * @param      pList 链表句柄
  */
void cotList_Clear(cotList_t *pList)
{
    Clear(pList);
    cotList_Init(pList);
}

/**
  * @brief      在链表某个元素后插入新的元素
  * 
  * @param      pList  链表句柄
  * @param      pListItem 被插入元素的指针
  * @param      pdata  新元素数据
  * @param      length 新元素数据长度
  */
void cotList_Insert(cotList_t *pList, cotListItem_t *pListItem, const void *pdata, uint32_t length)
{
    Insert(pList, pListItem, pdata, length);;
}

/**
  * @brief      在链表某个元素后插入新的元素
  * 
  * @attention  需要定义一个链表元素后才能添加
  * @param      pList   链表句柄
  * @param      pListItem 被插入元素的指针
  * @param      pNewItem  新的元素指针
  */
void cotList_InsertItem(cotList_t *pList, cotListItem_t *pListItem, cotListItem_t *pNewItem)
{
    pNewItem->pPrev = pListItem->pPrev;
    pNewItem->pNext = pListItem;

    pListItem->pPrev->pNext = pNewItem;
    pListItem->pPrev = pNewItem;
    pList->count++;
}

/**
  * @brief      擦除其中一个元素
  * 
  * @param      pList   链表句柄
  * @param      pListItem 被删除元素的指针
  * @return     被删除元素的指针的下一个元素
  */
cotListItem_t * cotList_Erase(cotList_t *pList, cotListItem_t *pListItem)
{
    cotListItem_t *ret = pListItem->pNext;
    Erase(pList, pListItem);
    return ret;
}

/**
  * @brief      推送一个元素到链表头部
  * 
  * @param      pList 链表句柄
  * @param      pdata  新元素数据
  * @param      length 新元素数据长度
  */
void cotList_PushFront(cotList_t *pList, const void *pdata, uint32_t length)
{
    Insert(pList, cotList_Begin(pList), pdata, length);
}

/**
  * @brief      从链表头部弹出一个元素
  * 
  * @param      pList 链表句柄
  */
void cotList_PopFront(cotList_t *pList)
{
    Erase(pList, cotList_Begin(pList));
}

/**
  * @brief      推送一个元素到链表尾部
  * 
  * @param      pList 链表句柄
  * @param      pdata  新元素数据
  * @param      length 新元素数据长度
  */
void cotList_PushBack(cotList_t *pList, const void *pdata, uint32_t length)
{
    Insert(pList, cotList_End(pList), pdata, length);
}

/**
  * @brief      从链表尾部弹出一个元素
  * 
  * @param      pList 链表句柄
  */
void cotList_PopBack(cotList_t *pList)
{
    Erase(pList, cotList_End(pList)->pPrev);
}

/**
  * @brief      两个链表内存进行交换
  * 
  * @param      pList     被交换的链表句柄
  * @param      pNewList  交换的链表句柄
  */
void cotList_Swap(cotList_t *pList, cotList_t *pNewList)
{
    *pNewList = *pList;
    pList->node.pPrev->pNext = &pNewList->node;
    pList->node.pNext->pPrev = &pNewList->node;
    cotList_Init(pList);
}

